"""
This module takes objects have been "compiled" previously and returns them as not-quite JSON - the objects are included so that the eval() returns already compiled objects. This saves some work on the client.

THIS MODULE DOES NOT PRODUCE JSON-COMPATIBLE OUTPUT! It's pure Javascript, but because it includes objects that we *assume* live on the client-side already, it's not pure JSON.

NOTE: this requires hacking simplejson because it tries to reencode whatever the "default" function comes up with. We provide the final JS and we don't want it to be postprocessed.
"""

import simplejson
from pythontojavascript.compilers import NotCompiledError

class PythonObjectEncoder(simplejson.JSONEncoder):
  def __init__(self,**kwargs):
    simplejson.JSONEncoder.__init__(self,**kwargs)
    
  def default(self,obj):
    """
    simplejson doesn't handle certain objects - we do that here.
    """
    js = u"new %(name)s(%(value)s)"
    
    stringify = ["datetime","timedelta"]
    if obj.__class__.__name__ in stringify:
      return str(obj)

    # DO WE REALLY WANT THIS DEFAULT BEHAVIOR?
    #print "iteator:",getattr(obj,"__itr__"
    if hasattr(obj,"__iter__"):
      # We have an iterator. Listify it.
      return list(obj)

    # Handle our main case - Compiled Objects - here
    if not hasattr(obj,"_PTJS_serialize"):
      raise NotCompiledError(
            "It looks like the object %s (type: %s) hasn't been compiled." 
             % (obj,type(obj)))
    properties = getattr(obj,"_PTJS_serialize")
    # This prevents PythonObject from thinking that we're creating an object
    output = {"_PTJS_FromServer":True}
    for p in properties:
      output[p] = getattr(obj,p)
    return js % {"name":obj.__class__.__name__,
                 "value":simplejson.dumps(output,cls=PythonObjectEncoder),
                 }

def encode(objects):
  return "(" + simplejson.dumps(objects,cls=PythonObjectEncoder) + ")"
